package tawai;

import java.io.IOException;
import java.util.Timer;
import java.util.TimerTask;
import javax.microedition.lcdui.game.Sprite;

/**
 * Class models Tank war machine
 *
 * @author Alex
 */
public class Tank implements IterativelyActive, Drawable {

    /**
     * Direction in degrees counterclockwise relative to X axis
     */
    public int dir;

    /**
     * Movement step
     */
    public int step;

    /**
     * Associated sprite
     */
    private Sprite sprite;

    /**
     * True if tank should move
     */
    private boolean moving;

    /**
     * Determines either this tank is allowed to shoot or not
     */
    private boolean shootingAllowed;

    /**
     * Timer responsible for counting cooldown time
     */
    private Timer cooldownTimer;

    /**
     * Shooting cooldown in ms
     */
    private static final int COOLDOWN = 500;

    /**
     * Coordinates of the point where shells should be spawned
     */
    private int gunPointX;
    private int gunPointY;

    /**
     * Am I alive?
     */
    private boolean alive = true;

    /**
     * Player who possesses this vehicle
     */
    private Player player;
    
    /**
     * Constructor
     * @param initX x-coordinate of the new tank
     * @param initY y-coordinate of the new tank
     * @param initDir Initial tank's direction
     * @param initSprite {@link Sprite} object associated with this tank
     * @param iniPlayer {@link Player} who possesses the tank
     */
    public Tank (int initX,
            int initY,
            int initDir,
            Sprite initSprite,
            Player iniPlayer) {

        dir = initDir;
        sprite = initSprite;
        step = 3;
        // Setting sprite position.
        // Moving reference pixel to the center
        sprite.setPosition(initX, initY);
        sprite.defineReferencePixel(sprite.getWidth()/2, sprite.getHeight()/2);
        sprite.defineCollisionRectangle(0, - step, sprite.getWidth(), sprite.getHeight() + step);
        player = iniPlayer;
        moving = false;
        shootingAllowed = true;
    }

    /**
     * Changing tank's coordinates so that it move forward according to current direction
     * 
     */
    public void move() {

        switch(dir) {
            case 0:
                sprite.setRefPixelPosition(sprite.getRefPixelX() + step, sprite.getRefPixelY());
                break;
            case 90:
                sprite.setRefPixelPosition(sprite.getRefPixelX(), sprite.getRefPixelY() - step);
                break;
            case 180:
                sprite.setRefPixelPosition(sprite.getRefPixelX() - step, sprite.getRefPixelY());
                break;
            case 270:
                sprite.setRefPixelPosition(sprite.getRefPixelX(), sprite.getRefPixelY() + step);
                break;
        }
    }

    /**
     * Method returns associated sprite
     * 
     * @return Associated {@link Sprite} object
     */
    public Sprite getSprite() {

        return sprite;
    }

    /**
     * Getter for tank's <code>x</code> coordinate.<br>
     *  
     * @return <code>x</code> coordinate of tank sprite's reference pixel which is it's center
     */
    public int getX() {

        return sprite.getRefPixelX();
    }

    /**
     * Getter for tank's <code>y</code> coordinate.<br>
     * 
     * @return <code>y</code> coordinate of tank sprite's reference pixel which is it's center
     */
    public int getY() {

        return sprite.getRefPixelY();
    }

    /**
     * Rotates sprite according to current tank direction
     */
    private void adjustSpriteDirection() {

        switch (dir) {
            case 0:
                sprite.setTransform(Sprite.TRANS_ROT90);
                break;
            case 90:
                sprite.setTransform(Sprite.TRANS_NONE);
                break;
            case 180:
                sprite.setTransform(Sprite.TRANS_ROT270);
                break;
            case 270:
                sprite.setTransform(Sprite.TRANS_ROT180);
                break;
        }

    }

    /**
     * Tank's iterative action lies in moving<br>
     * 
     * @see IterativelyActive
     */
    public void performIterativeAction() {

        // Moving and playing movement animation
        if (moving && alive && checkMovingPermission()) {
            move();
            sprite.nextFrame();
        }

    }

    /**
     * Method is called when tank shoots
     * 
     */
    public void shoot() {

        // Checking tank's states
        if (!alive || !shootingAllowed)
            return;

        // Calculating coordinates of the point where fired shell should be spawned
        switch (dir) {
            case 0:
                gunPointX = sprite.getRefPixelX() + sprite.getHeight()/2 + 2 *step;
                gunPointY = sprite.getRefPixelY();
                break;
            case 90:
                gunPointY = sprite.getRefPixelY() - sprite.getHeight()/2 - 2 * step;
                gunPointX = sprite.getRefPixelX();
                break;
            case 180:
                gunPointX = sprite.getRefPixelX() - sprite.getHeight()/2 - 2 * step;
                gunPointY = sprite.getRefPixelY();
                break;
            case 270:
                gunPointY = sprite.getRefPixelY() + sprite.getHeight()/2 + 2 * step;
                gunPointX = sprite.getRefPixelX();
                break;
        }

        // Spawning shell
        TawaiMIDlet.getMain().addSceneObject(new Shell(dir, gunPointX, gunPointY));

        // Starting gun cooldown
        shootingAllowed = false;
        cooldownTimer = new Timer();
        cooldownTimer.schedule(new CooldownTimerTask(), COOLDOWN);
    }

    /**
     * Called when tank is shot by a shell
     */
    public void die() {

        alive = false;

        // Creating new fire sprite
        Sprite fire = null;
        try {
            fire = new Sprite(TawaiMIDlet.getMain().getGameDesign().getFireSprite());
        } catch (IOException ex) {
            ex.printStackTrace();
        }
        fire.setPosition(sprite.getX(), sprite.getY());
        TawaiMIDlet.getMain().addSceneObject(fire);

        // Notifying player that his vehicle was blown
        player.vehicleBlown();
    }

    /**
     * Causes tank to move forward according to current direction
     */
    public void startMoving() {

        moving = true;
    }

    /**
     * Stops the tank
     */
    public void stopMoving() {

        moving = false;
    }

    /**
     * Changes tank's direction
     * @param newDir New direction in degrees relative to <code>x</code> axis counterclockwise
     */
    public void setDir(int newDir) {

       if (!alive)
           return;

       dir = newDir;
       adjustSpriteDirection();
    }

    /**
     * Checks whether the tank is allowed to move or not
     * @return The result of a moving permission test
     */
    private boolean checkMovingPermission() {

        // Checking collisisons with ObstaclesLayer
        try {
            return !sprite.collidesWith(TawaiMIDlet.getMain().getGameDesign().getObstaclesLayer(), false);
        } catch (IOException ex) {
            ex.printStackTrace();
        }

        // If something wrong happens, disallow tank to move
        return false;
    }

    /**
     * Shooting cooldown counter
     */
    private class CooldownTimerTask extends TimerTask {

        public void run() {

            shootingAllowed = true;
        }

    }

}
